use reqwest::blocking::{Client};
use reqwest::Error;

use libc::{c_char, c_int, c_void, size_t, memcpy};

use std::time::Duration;
use std::ffi::{CStr, CString};

fn post_by_text(url: &str, body: &str) -> Result<String, Error> {
    let cli = Client::new();
    let ret = cli.post(url)
        .timeout(Duration::new(10, 0))
        .header("Content-Type", "application/json")
        .body(body.to_owned())
        .send()?
        .text()?;
    return Ok(ret);
}

#[no_mangle]
extern "C" fn rust_post_by_text(url: *const c_char, body: *const c_char, out: *mut c_char, out_len: c_int) -> c_int {
    let url_cstr = unsafe { CStr::from_ptr(url) };
    let url_str_r = url_cstr.to_str();
    let url_str = match url_str_r {
        Ok(v) => v,
        Err(_) => return -1,
    };

    let body_cstr = unsafe { CStr::from_ptr(body) };
    let body_str_r = body_cstr.to_str();
    let body_str = match body_str_r {
        Ok(v) => v,
        Err(_) => return -1,
    };

    let ret_r = post_by_text(url_str, body_str);
    let ret = match ret_r {
        Ok(v) => v,
        Err(_) => return -1,
    };

    let out_str_r = CString::new(ret);
    let out_str = match out_str_r {
        Ok(v) => v,
        Err(_) => return -1,
    };

    let out_str_len = out_str.as_bytes().len() as c_int;
    let out_cstr = out_str.as_c_str();
    let out_ptr = out_cstr.as_ptr();

    let out_ptr_len = if out_str_len > (out_len - 1) { out_len - 1 } else { out_str_len };

    unsafe {
        memcpy(out as *mut c_void, out_ptr as *const c_void, out_ptr_len as size_t);
    }
    return out_ptr_len;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        let result = 2 + 2;
        assert_eq!(result, 4);
    }
}
